package org.pih.migration.load.objects;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;

import org.pih.javarosa.migration.export.Row;
import org.pih.javarosa.migration.export.Worksheet;
import org.pih.util.NumericUtils;

public class WorksheetParser {

	public Protocol parse(Worksheet worksheet) {
		Protocol protocal = new Protocol();
		protocal.setName(worksheet.getName());
		Hashtable<String, Step> stepTable = new Hashtable<String, Step>();
		boolean inProcess = false;

		List<StepRaw> rawSteps = new ArrayList<StepRaw>();
		StepRaw stepRaw = null; 
		String cLevel = null;
		for (Row row : worksheet.getRows()) {
			if (inProcess == false && row.getItem().equals("A")) inProcess = true;
			if (inProcess) {
				if (row.getItem() != null && row.getItem().trim().length() > 0) {
					//Starting new step
					if (stepRaw != null) rawSteps.add(stepRaw);
					stepRaw = new StepRaw();
					if (row.getItem().toUpperCase().startsWith("C")) {
						cLevel = row.getItem();
						stepRaw.setId(row.getItem());
						stepRaw.setcLevel(cLevel);
					} else {
						stepRaw.setId((cLevel == null ? "" : cLevel + "_") + row.getItem());
						stepRaw.setcLevel(cLevel);
					}
					stepRaw.getRows().add(row);
				} else {
					//append row to stepRaw
					if (!row.isNull()) stepRaw.getRows().add(row);
				}
			}
		}
		if (stepRaw != null) rawSteps.add(stepRaw);
		//			dumpRawSteps(rawSteps);

		for (StepRaw tmpStepRaw : rawSteps) {
			if (tmpStepRaw.getId().equalsIgnoreCase("B")) {
				System.out.println("\nParsing step: " + worksheet.getName() + ":" + tmpStepRaw.getId());
				Row firstRow = tmpStepRaw.getRows().get(0);
				
				List<Drug> drugs = new ArrayList<Drug>();
				
				HashSet<Integer> distinctLocations = new HashSet<Integer>(); 
				
				
				for (Row row : tmpStepRaw.getRows()) {
					if (row.getLocation() != null && row.getLocation().trim().length() > 0) {
						Drug drug = new Drug();
						drug.setName(row.getContent().trim());
						drug.setValue(row.getContent().trim().replaceAll(" ", "_").toLowerCase());
						drug.setChildId(extractNextStep(row.getAction()));
//						step.getOptions().add(option);
						drug.addLocation(row.getLocation());
						
						for (Integer tmpLocationCode : drug.getAppliesTo()) distinctLocations.add(tmpLocationCode);
						
						
						drugs.add(drug);
					}
				}

				for (int tmpLocationCode : distinctLocations) {
//					System.out.println("Getting drugs for location: " + tmpLocationCode);
					Step step = new Step();
					step.setId("B" + tmpLocationCode);
					step.setPrompt(firstRow.getContent());
					step.setItemFormat(firstRow.getItemFormat());
					step.setItemType(firstRow.getItemType());
					List<Option> options = new ArrayList<Option>();
					for (Drug drug : drugs) {
						for (int locationCode : drug.getAppliesTo()) {
							if (locationCode == tmpLocationCode) {
								options.add((Option) drug);
							}
						}
					}
					step.setOptions(options);
					stepTable.put(step.getId(), step);
				}
			} else {
				System.out.println("\nParsing step: " + worksheet.getName() + ":" + tmpStepRaw.getId());
				Step step = null;
				for (Row row : tmpStepRaw.getRows()) {
					if (step == null) {
						step = new Step();
						step.setId(tmpStepRaw.getId());
						step.setItemFormat(row.getItemFormat());
						step.setItemType(row.getItemType());
						step = extractOptionsFromRow(tmpStepRaw.getId(), step, tmpStepRaw.getcLevel(), row);
						step = updateChildId(row, step, tmpStepRaw.getcLevel());
					} else {
						step = extractOptionsFromRow(tmpStepRaw.getId(), step, tmpStepRaw.getcLevel(), row);
						step = updateChildId(row, step, tmpStepRaw.getcLevel());
					}
				}
				if (step != null) {
					if (step.getId().equalsIgnoreCase("C14_FF1")) {
						System.out.println("C14_FF1");
					}
					
					
					if (step.getOptions().size() == 0) {
						// Then we're done
						Option option = new Option();
						option.setName("Done");
						option.setValue("done");
						option.setChildId("done");
						step.getOptions().add(option);
					}
					
					System.out.println(step.getId() + ": " + step.toString());
					stepTable.put(step.getId(), step);
				}
			}
			
		}



		//			if (step != null) stepTable.put(step.getId(), step);
		protocal.setStepTable(stepTable);

		//dumpStepTable(stepTable);

		return protocal;

	}

	@SuppressWarnings("unused")
	private void dumpRawSteps(List<StepRaw> rawSteps) {
		for (StepRaw stepRaw : rawSteps) {
			System.out.println(stepRaw.getId());
			for (Row row : stepRaw.getRows()) {
				System.out.println("        Row: " + row.toString());
			}
		}
	}

	@SuppressWarnings({ "unused", "rawtypes" })
	private void dumpStepTable(Hashtable stepTable) {
		Enumeration e = stepTable.keys();

		while(e.hasMoreElements()) {
			Step step = (Step) stepTable.get(e.nextElement());

			System.out.println(step.getId());
			System.out.println("   >> " + step.getPrompt());
			if (step.getOptions() != null) {
				System.out.println("      Options: ");
				for (Option option : step.getOptions()) {
					if (option.getValue() != null) {
						System.out.println("             " + option.getValue() + ") " + option.getName() + " (" + option.getChildId() + ")");
					} else if (option.getChildId() != null) {
						System.out.println("             Go To: " + option.getChildId());
					}
				}
			}
		}
	}

	private Step updateChildId(Row row, Step step, String cLevel) {
		String childId = null;

		if (step.getItemType().equalsIgnoreCase("Question")) {
			childId = extractNextStep(row.getAction());
			String whenId = row.getOptions();
//			if (whenId == null || whenId.trim().length() == 0 || !isInt(whenId)) {
			if ((whenId == null || whenId.trim().length() == 0) && row.getAction() != null && row.getAction().trim().length() > 0) {
				System.err.println("Parsing error: please review and repair row: " + row.toString());
			} else {
				if (NumericUtils.isInt(whenId) && childId != null && childId.length() > 0) {
					Option option = step.getOptions().get(Integer.parseInt(whenId) - 1);
					option.setChildId((cLevel != null ? cLevel + "_" : "") + childId);
					step.getOptions().set(Integer.parseInt(whenId) - 1, option);
				}
			}
		}

		return step;
	}

	private Step extractOptionsFromRow(String id, Step step, String cLevel, Row row) {
		//		Content content = new Content();
		List<Option> options = new ArrayList<Option>();

		if (row.getItemType() != null && row.getItemType().trim().equalsIgnoreCase("Action")) {
			step.setPrompt(row.getContent());
			Option option = new Option();
			String action = extractNextStep(row.getAction());
			
			if ((row.getOptions() == null || row.getOptions().trim().length() == 0) && (row.getAction() == null || row.getAction().trim().length() == 0)) {
				option.setName("Done");
				option.setValue("done");				
				option.setChildId("done");
			} else {
//				option.setName(row.getOptions());
//				option.setValue(row.getOptions());
				if (action != null && action.trim().length() > 0) {
					option.setChildId((cLevel != null ? cLevel + "_" : "") + action);	
					option.setName("Continue");
					option.setValue("continue");
				} else {
					option.setName("Done");
					option.setValue("done");				
					option.setChildId("done");
				}
			}
			
			options.add(option);
			step.setOptions(options);
		} else {
			if (id.equalsIgnoreCase("A")) {
				if (row.getItem() != null && row.getItem().equals("A")) step.setPrompt(row.getContent());
				String[] parsedOptions = row.getOptions().trim().split("[0-9]\\)");

				int optionNo = 1;
				for (String tmpOption : parsedOptions) {
					if (tmpOption.trim().length() > 0) {
//						System.out.println("parsedOptions: tmpOption: " + tmpOption);
						Option option = new Option();
						option.setName(tmpOption.trim());
						option.setValue("" + optionNo);
						option.setChildId("B" + optionNo++);
						options.add(option);
					}
				}
				step.setOptions(options);
			} else if (id.equalsIgnoreCase("B")) {
				if (row.getItem() != null && row.getItem().trim().equals("B")) step.setPrompt(row.getContent());
				if (row.getOptions().equalsIgnoreCase("Continue")) {
					Option option = new Option();
					option.setName(row.getContent());
					option.setValue(row.getContent());
					option.setChildId(extractNextStep(row.getAction()));
					step.getOptions().add(option);
				}
			} else {
				if (row.getContent() != null && row.getContent().indexOf("1)") > -1) {
					String tmpContent = row.getContent();
					boolean skipPrompt = false;
					if (row.getItem() != null && row.getItem().trim().length() > 0) {
						String prompt = row.getContent().substring(0, row.getContent().indexOf("1)")).trim();
						tmpContent = row.getContent().substring(row.getContent().indexOf("1)")).trim();
						step.setPrompt(prompt);
						skipPrompt = true;
					}

					String[] parsedOptions = tmpContent.split("[0-9]\\)");

					if (row.getContent().trim().indexOf("1)") > 1) skipPrompt = true;

					int optionNo = 1;
					for (String tmpOption : parsedOptions) {
						if (skipPrompt) {
							skipPrompt = false;
						} else {
							Option option = new Option();
							option.setName(tmpOption.trim());
							option.setValue("" + optionNo++);
							options.add(option);						
						}
					}
					step.setOptions(options);
				}
			}
		}

		return step;
	}

	private String extractNextStep(String action) {
		if (action != null && action.toLowerCase().indexOf("go to") > -1) {
			return (action.toUpperCase()).replaceAll("GO TO", "").trim();
		}
		return null;
	}

}
